<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Test for syncbase targetting</title>
  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px"
     onload="this.pauseAnimations()">
  <circle cx="-20" cy="20" r="15" fill="blue" id="circle">
    <set attributeName="cx" to="0" begin="2s" dur="1s" id="a"/>
    <set attributeName="cx" to="0" begin="2s" dur="1s" xml:id="b"/>
    <set attributeName="cx" to="0" begin="2s" dur="1s" id="あ"/>
    <set attributeName="cx" to="0" begin="2s" dur="1s" id="a.b"/>
    <set attributeName="cx" to="0" begin="2s" dur="1s" id="a-b"/>
    <set attributeName="cx" to="0" begin="2s" dur="1s" id="a:b"/>
    <set attributeName="cx" to="0" begin="2s" dur="1s" id="-a"/>
    <set attributeName="cx" to="0" begin="2s" dur="1s" id="0"/>
  </circle>
</svg>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
/** Test for syncbase targetting behavior  **/

SimpleTest.waitForExplicitFinish();

function main() {
  var svg = getElement("svg");
  ok(svg.animationsPaused(), "should be paused by <svg> load handler");
  is(svg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");

  testSpecs();
  testChangeId();
  testRemoveTimebase();

  SimpleTest.finish();
}

function testSpecs() {
  var anim = createAnim();

  // Sanity check--initial state
  ok(noStart(anim), "Unexpected initial value for indefinite start time.");

  var specs = [ [ 'a.begin', 2 ],
                [ 'b.begin', 'todo' ], // xml:id support, bug 275196
                [ 'あ.begin', 2 ],   // unicode id
                [ ' a.begin ', 2 ],  // whitespace
                [ 'a\\.b.begin', 2 ], // escaping
                [ 'a\\-b.begin', 2 ], // escaping
                [ 'a:b.begin', 2 ],
                // Invalid
                [ '-a.begin', 'notok' ], // invalid XML ID
                [ '\\-a.begin', 'notok' ], // invalid XML ID
                [ '0.begin', 'notok' ], // invalid XML ID
                [ '\xB7.begin', 'notok' ], // invalid XML ID
                [ '\x7B.begin', 'notok' ], // invalid XML ID
                [ '.begin', 'notok' ],
                [ '  .end  ', 'notok' ],
                [ 'a.begin-5a', 'notok' ],
                // Offsets
                [ ' a.begin + 1min', 2 + 60 ],
                [ ' a.begin-0.5s', 1.5 ],
              ];
  for (var i = 0; i < specs.length; i++) {
    var spec = specs[i][0];
    var expected = specs[i][1];
    anim.setAttribute('begin', spec);
    try {
      if (typeof(expected) == 'number') {
        is(anim.getStartTime(), expected,
           "Unexpected start time with spec: " + spec);
      } else if (expected == 'todo') {
        todo_is(anim.getStartTime(), 2,"Unexpected success with spec: " + spec);
      } else {
        anim.getStartTime();
        ok(false, "Unexpected success with spec: " + spec);
      }
    } catch(e) {
      if (e.name == "InvalidStateError" &&
          e.code == DOMException.INVALID_STATE_ERR) {
        if (typeof(expected) == 'number')
          ok(false, "Failed with spec: " + spec);
        else if (expected == 'todo')
          todo(false, "Yet to implement: " + spec);
        else
          ok(true);
      } else {
        ok(false, "Unexpected exception: " + e + "(with spec: " + spec + ")");
      }
    }
  }

  anim.parentNode.removeChild(anim);
}

function testChangeId() {
  var anim = createAnim();

  anim.setAttribute('begin', 'a.begin');
  is(anim.getStartTime(), 2, "Unexpected start time.");

  var a = getElement('a');
  a.setAttribute('id', 'a1');
  ok(noStart(anim), "Unexpected return value after changing target ID.");

  a.setAttribute('id', 'a');
  is(anim.getStartTime(), 2,
     "Unexpected start time after resetting target ID.");

  anim.parentNode.removeChild(anim);
}

function testRemoveTimebase() {
  var anim = createAnim();
  anim.setAttribute('begin', 'a.begin');
  ok(!noStart(anim), "Unexpected start time before removing timebase.");

  var circle = getElement('circle');
  var a = getElement('a');
  // Sanity check
  is(a, circle.firstElementChild, "Unexpected document structure");

  // Remove timebase
  a.parentNode.removeChild(a);
  ok(noStart(anim), "Unexpected start time after removing timebase.");

  // Reinsert timebase
  circle.insertBefore(a, circle.firstElementChild);
  ok(!noStart(anim), "Unexpected start time after re-inserting timebase.");

  // Remove dependent element
  anim.parentNode.removeChild(anim);
  ok(noStart(anim), "Unexpected start time after removing dependent.");

  // Create a new dependent
  var anim2 = createAnim();
  anim2.setAttribute('begin', 'a.begin');
  is(anim2.getStartTime(), 2,
     "Unexpected start time after adding new dependent.");
}

function createAnim() {
  const svgns="http://www.w3.org/2000/svg";
  var anim = document.createElementNS(svgns,'animate');
  anim.setAttribute('attributeName','cx');
  anim.setAttribute('from','0');
  anim.setAttribute('to','100');
  anim.setAttribute('begin','indefinite');
  anim.setAttribute('dur','1s');
  return getElement('circle').appendChild(anim);
}

function noStart(elem) {
  var exceptionCaught = false;

  try {
    elem.getStartTime();
  } catch(e) {
    exceptionCaught = true;
    is (e.name, "InvalidStateError",
        "Unexpected exception from getStartTime.");
    is (e.code, DOMException.INVALID_STATE_ERR,
        "Unexpected exception code from getStartTime.");
  }

  return exceptionCaught;
}

window.addEventListener("load", main, false);
]]>
</script>
</pre>
</body>
</html>
